package com.ms.service.module.processer;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Random;

import com.ms.game.common.GameType;
import com.ms.game.lobby.message.SimpleKeepData;
import com.ms.game.mgdh.message.SDoorManCancelOfflineKeepDataRequest;
import com.ms.game.slot.base.SlotWaterDisappearRedisSys;
import com.ms.game.slot.base.SlotWaterDisappearSystem;
import com.ms.game.slot.base.message.CSlotCommonUseGameCardRequest;
import com.ms.game.slot.base.message.SDMDoSeatRequest;
import com.ms.game.slot.base.message.SDMSeatStatChangeRequest;
import com.ms.game.slot.base.message.SlotBasicDMMessageRequest;
import com.ms.game.slot.base.message.SlotGameAsyncDoSeatDataRequest;
import com.ms.game.slot.base.message.SlotGameDoSeatVerifyRequest;
import com.ms.game.slot.base.message.SlotGameLeaveBackRequest;
import com.ms.game.slot.base.message.SlotGameLeaveRequest;
import com.ms.player.Player;
import com.ms.service.module.analysis.AnalysisProcessor;
import com.ms.service.module.analysis.PlayerEnterSeatStatusType;
import com.ms.service.module.datacenterlite.GameCancelKeepDataAyncCommand;
import com.ms.service.module.datacenterlite.GameGetKeepSeatAyncCommand;
import com.ms.service.module.datacenterlite.GameKeepSeatData;
import com.ms.service.module.datacenterlite.GameModifyKeepSeatAysncCommand;
import com.ms.service.module.datacenterlite.constant.DCLiteMessageType;
import com.xpec.c4.game.common.Helper;
import com.xpec.c4.game.datamanager.BaseDataInfo;
import com.xpec.c4.game.datamanager.agent.PlayerData;
import com.xpec.c4.game.datamanager.agent.PlayerDataAgent;
import com.xpec.c4.game.time.TimeSys;
import com.xpec.c4.game.utility.GUID;
import com.xpec.c4.service.common.BaseMessageAction;
import com.xpec.c4.service.group.transportlayer.GroupMessage;
import com.xpec.c4.service.message.MessageAction;
import com.xpec.c4.service.module.BasicServiceModule;
import com.xpec.c4.service.module.ConsistentGroupName;
import com.xpec.c4.service.module.common.PlayerCommonInfoManager;
import com.xpec.c4.service.module.task.TaskAsyncCommand;

/**
 * processer 基底類別
 * @author TW15012
 *
 */
public class BasiceServiceProcesser<T>
{
	protected SlotWaterDisappearSystem<T> waterDisappear = new SlotWaterDisappearSystem<T>();
	
	protected Random ran = new Random();
	
	protected BaseMessageAction baseaction;
	
	protected String modelName;

	protected int queueidx=0;
	
	
	private static HashMap<String , Long> benchmark = new HashMap<String , Long>();
	
	public String getModelName() {
		return modelName;
	}

	public void setModelName(String modelName) {
		this.modelName = modelName;
	}
	
	public BaseMessageAction getBaseaction() {
		return baseaction;
	}

	public void setBaseaction(BaseMessageAction baseaction) {
		this.baseaction = baseaction;
	}
	
	/**
	 * 讀取玩家遊戲群組目標Moduleid
	 * @param groupid
	 * @param guid
	 * @return
	 */
	public String getTargetID(String groupid , GUID guid)
	{
		BasicServiceModule module = baseaction.getModule();
		return module.lookUp(groupid , guid);
	}
	
	/**
	 * 讀取遊戲桌目標Moduleid
	 * @param groupid
	 * @param guid
	 * @return
	 */
	public String getTargetIDByTable(String groupid , String tableid)
	{
		return ConsistentGroupName.lookUpByString(groupid, tableid);
	}

	/**
	 * 新增任務至子執行緒
	 * @param task
	 */
	public void addTaskToModule(TaskAsyncCommand task)
	{
		if(queueidx == (baseaction.getModule()).asyncTaskQueueCount-2)
		{
			queueidx = 0;
		}
		else
		{
			queueidx++;
		}
		
		task.setQueueID(queueidx);
		//task.queueID =ran.nextInt() % (baseaction.getModule()).asyncTaskQueueCount;
		task.moduleServer = baseaction.getModule();
		baseaction.getModule().addAsyncCommand(task);
	}
	
	/**
	 * 記錄執行開始時間
	 * @param key
	 */
	public static void startBenchMark(String key)
	{
		if(benchmark.containsKey(key))
		{
			System.out.println("BenchMark Key Already Exists ["+key+"]");
			
			benchmark.remove(key);
			return;
		}
		
		benchmark.put(key, TimeSys.currentTimeMills());
	}
	
	/**
	 * 顯示執行時間
	 * @param key
	 */
	public static void endBenchMark(String key)
	{
		if(!benchmark.containsKey(key))
		{
			System.out.println("BenchMark Key Not Find ["+key+"]");
			return;
		}
		
		long end = TimeSys.currentTimeMills();
		long start = benchmark.get(key);
		
		System.out.println("******** ["+key+"] Total  Waster Time = [ " + (end-start) + " ] ms ************");
		
		benchmark.remove(key);
	}
	
	
	/**
	 * 
	 * @param agent
	 *            data agent
	 * @param player
	 *            player guid
	 * @param func
	 *            callback method name<br>
	 *            method example:<br>
	 *            public void onGetPlayerFromDC(PlayerData playerData, Object... userObject)
	 * @param userObject
	 *            user object
	 * @throws ClassNotFoundException
	 */
	public void onGetPlayerData(PlayerDataAgent agent ,GUID player , String func  , Object...userObject) throws ClassNotFoundException
	{
		DMDoSeatGetPlayerAsync async = new DMDoSeatGetPlayerAsync();
		async.initial(player, baseaction.getSessionID());
		async.initial2(baseaction, "onPlayerDataAgentBack" , func ,userObject);
		
		getBaseaction().getModule().addAsyncCommand(async);
	}
	
	/**
	 * dc player data call back
	 * @param obj
	 * @param userObject
	 * @throws NoSuchMethodException
	 * @throws SecurityException
	 * @throws IllegalAccessException
	 * @throws IllegalArgumentException
	 * @throws InvocationTargetException
	 * @throws ClassNotFoundException
	 */
	public  void onPlayerDataAgentBack(BaseDataInfo obj,Object... userObject) throws NoSuchMethodException, SecurityException, IllegalAccessException, IllegalArgumentException, InvocationTargetException, ClassNotFoundException
	{
		try
		{
					String method_name = (String)userObject[0];
					Method method =  this.getClass().getDeclaredMethod(method_name, new Class[]{PlayerData.class,Object[].class});
					method.setAccessible(true);
					method.invoke(this, (PlayerData) obj , userObject);
		}
		catch(Exception ex)
		{
			//log.debug(ex);
		}
		
	}
	
	/**
	 * 讀取玩家保留機台資料<br>
	 * callback 參考: {@link Slot3X3HalloweenDMProcesser#onGetPlayerKeepDataCallBack(ArrayList, Object...)}
	 */
	public void getPlayerKeepData(GameGetKeepSeatAyncCommand cmd , String method ,Object... userObj)
	{
		cmd.callbackMethod = method;
		this.baseaction.getModule().addCentralAsyncCommand(cmd, userObj);
	}
	
	
	/**
	 * 更新玩家保留機台資料<br>
	 * callback 參考: {@link Slot3X3HalloweenDMProcesser#onUpdatePlayerKeepDataCallBack(int, Object...)}
	 * @param cmd
	 * @param method
	 * @param userObj
	 */
	public void updatePlayerKeepData(GameModifyKeepSeatAysncCommand cmd , String method ,Object... userObj)
	{
		cmd.callbackMethod = method;
		this.baseaction.getModule().addCentralAsyncCommand(cmd, userObj);
	}

	/**
	 * 大廳通知刪除離線保留資格
	 * 
	 * @param reuqest
	 * @param type
	 *            {@link DCLiteMessageType}
	 */
	public  void revLobbyCancelOfflineKeepData(SDoorManCancelOfflineKeepDataRequest reuqest , int type)
	{
		SimpleKeepData data = reuqest.getData();
		GUID sessionid = baseaction.getSessionID();
		String srcMID = baseaction.getSrcService();
		
		GameCancelKeepDataAyncCommand cmd = new GameCancelKeepDataAyncCommand();
		cmd.methodType = type;
		cmd.gameName =data.game;
		cmd.halltype = data.halltype;
		cmd.playerGUID =reuqest.getPlayerGUID().toString();
		cmd.seatid = data.seatid;
		cmd.machineid =data.machineid;
		cmd.isofflinekeep = true;
		
		this.baseaction.getModule().addCentralAsyncCommand(cmd, reuqest , sessionid , srcMID);
	}
	
	
	
	/**
	 * get keep data call back
	 * @throws SecurityException 
	 * @throws NoSuchMethodException 
	 * @throws InvocationTargetException 
	 * @throws IllegalArgumentException 
	 * @throws IllegalAccessException 
	 */
	public void onGetKeepDataCallBack(ArrayList<GameKeepSeatData> list , String callbackmethod , Object... userObject) throws NoSuchMethodException, SecurityException, IllegalAccessException, IllegalArgumentException, InvocationTargetException 
	{
		Method method =  this.getClass().getDeclaredMethod(callbackmethod, new Class[]{ArrayList.class,Object[].class});
		method.setAccessible(true);
		method.invoke(this, list, userObject);
	}
	
	/**
	 * update keep data call back
	 */
	public void onUpdatePlayerKeepDataCallBack(int result  , String callbackmethod  , Object... userObject) throws NoSuchMethodException, SecurityException, IllegalAccessException, IllegalArgumentException, InvocationTargetException 
	{
		Method method =  this.getClass().getDeclaredMethod(callbackmethod, new Class[]{int.class,Object[].class});
		method.setAccessible(true);
		method.invoke(this,result , userObject);
	}
	
	/**
	 * 玩家入座
	 */
	public void revDMDoSeat(SDMDoSeatRequest request)
	{
		
	}
	
	/**
	 * 座位狀態更新 - DM
	 */
	public void revDMSeatStatchange(SDMSeatStatChangeRequest request)
	{
		
	}
	
	/**
	 * 讀取保留資料
	 */
	public void onGetKeepDataBack(ArrayList<GameKeepSeatData> list , Object... userObject)
	{
		
	}
	
	/**
	 * 更新保留資料回呼
	 * @param result
	 * @param userObject
	 */
	public void onUpdatePlayerKeepDataBack(int result , Object... userObject)
	{
		
	}
	
	/**
	 * 玩家離座 - for Game Server
	 */
	public void revGameLeave(SlotGameLeaveRequest request)
	{
		
	}
	
	/**
	 * 玩家使用機台卡 </br> 
	 * for Game Server </br>
	 */
	public void revUseGameCardRequest(CSlotCommonUseGameCardRequest request)
	{
		
	}
	
	/**
	 * 使用道具 的 DC call back</br>
	 * for Game Server </br>
	 * @param obj
	 * @param userObject
	 */
	public void onUpdateUseGameCardBack(BaseDataInfo obj, Object... userObject) {
		
	}
	
	
	
	/**
	 * player common 讀取玩家資料回呼
	 */
	public void doSeatPlayerDataBack(PlayerData playerData, Object[] userObject)
	{
		
	}
	
	/**
	 * 玩家入座驗證
	 * @param request
	 */
	public void revDoSeatVerify(SlotGameDoSeatVerifyRequest request)
	{
		
	}
	
	/**
	 * 同步
	 * @param request
	 */
	public void revAsyncDoSeatData(SlotGameAsyncDoSeatDataRequest request)
	{
		
	}
	
	/**
	 * dm 離座處理完回呼game server
	 * @param request
	 */
	public void revLeaveSeatBack(SlotGameLeaveBackRequest request)
	{
		
	}
	
	/**
	 * 驗證過期game to dm
	 * @param request
	 */
	public void revVerifyExpried(SlotBasicDMMessageRequest request)
	{
		
	}
	
	/**
	 * 傳送資料給client
	 * 
	 * @param messagetype
	 * @param response
	 * @param sessionid
	 */
	public static void sendMessageToClient(GUID sessionid, int messagetype, Object response) {
		MessageAction.sendMessage(sessionid, messagetype, response);
	}

	/**
	 * 傳送 group message
	 * 
	 * @param messageType
	 * @param messageContent
	 * @param destModuleId
	 * @param srcModuleId
	 *            可以給可以不給，不想給就填 null
	 */
	public static void sendGroupMessage(int messageType, Object messageContent, String destModuleId,
			String srcModuleId) {
		GroupMessage msg = new GroupMessage();
		msg.setMessageType(messageType);
		msg.setMessageContent(messageContent);
		msg.setDestModuleID(destModuleId);
		msg.setSrcService(srcModuleId);
		MessageAction.sendGroupMessage(msg);
	}
	
	/**
	 * 傳送玩家入離座狀態
	 * @param sessionId
	 * @param guid
	 * @param game
	 * @param halltype
	 * @param machineId
	 * @param type
	 * @param player
	 */
	public void sendPlayerEnterSeat
	(
				GUID sessionId, 
				GUID guid , 
				GameType game , 
				String halltype , 
				int machineId , 
				int gainRateID,
				PlayerEnterSeatStatusType type,
				Player player
	)
	{
		String platform =(player==null)?  
										PlayerCommonInfoManager.getInstance().getLoginPlatformBySessionId(sessionId):
										player.getLastLoginPlatform();
										
		String nickname = (player==null)? 
										PlayerCommonInfoManager.getInstance().getPlayerNameByGuid(guid):
										player.getNameWithNumber();
		
		int userType = (player==null)? 0:player.getUserType();
		boolean isTrialAccount =  (player==null)? false:player.isTrialAccount();
		boolean isUseTrialCoin = (player==null)? false:player.isUseTrialCoin();
		
		AnalysisProcessor.sendPlayerEnterSeat
		(
				nickname,
				guid.toString(),
				platform,
				game,
				halltype, 
				machineId,
				gainRateID,
				type, 
				userType, 
				isTrialAccount, 
				isUseTrialCoin
		);
	}

	/**
	 * 廣播機台更新資訊給 client 的計時器觸發
	 */
	public void onSlotDmSeatHistoryBroadcastTimer() {

	}
	
	/**
	 * 咬幣潮 - 重置菜鳥、一般水庫
	 * @param model
	 * @throws SecurityException 
	 * @throws NoSuchMethodException 
	 * @throws InvocationTargetException 
	 * @throws IllegalArgumentException 
	 * @throws IllegalAccessException 
	 */
	public void doWaterDisappear(String halltype , String modelName)
	{
		try
		{
				//更新座位為0的
				List<T> data = waterDisappear.getStateEmpty(modelName);
				for(T mm:data)
				{
					setModelWaterReset(mm);
					waterDisappear.modifyModel(mm);
				}
				
				//將座位不為0的塞入redis
				List<T> rdata = waterDisappear.getStateNotEmtpy(modelName);
				if(rdata.size()>0)
				{
					ArrayList<String> list = new ArrayList<String>();
					for(T m:rdata)
					{
						list.add((String) m);
					}
					SlotWaterDisappearRedisSys.setFlagToRedis(halltype,list);
				}
		}
		catch(Exception ex)
		{
			ex.printStackTrace();
		}
	}
	
	/**
	 * 執行咬幣潮 - 直接設定成清水模式
	 */
	@SuppressWarnings("rawtypes")
	public  T setModelWaterReset(T model)
	{
		Class[] cDecimalArg = new Class[1];
		cDecimalArg[0] = BigDecimal.class;
		
		
		Class[] cStringArg = new Class[1];
		cStringArg[0] = String.class;
		
		
		ArrayList<Method> listDecimal = new ArrayList<Method>();
		ArrayList<Method> listStr = new ArrayList<Method>();
		
		
		try 
		{
			 Method m_setWaterpool = model.getClass().getMethod("setWaterpool", cDecimalArg);
			 
			 Method m_setPourBase = model.getClass().getMethod("setPourBase", cDecimalArg);
			 Method m_setPourStart = model.getClass().getMethod("setPourStart", cDecimalArg);
			 Method m_setPourTotal = model.getClass().getMethod("setPourTotal", cDecimalArg);
			
			 
			 Method m_setRookie_pourBase = model.getClass().getMethod("setRookie_pourBase", cDecimalArg);
			 Method m_setRookie_pourStart = model.getClass().getMethod("setRookie_pourStart", cDecimalArg);
			 Method m_setRookie_pourTotal = model.getClass().getMethod("setRookie_pourTotal", cDecimalArg);
			 Method m_setRookie_waterpool = model.getClass().getMethod("setRookie_waterpool", cDecimalArg); 
			 
			 Method m_setRookie_pourState = model.getClass().getMethod("setRookie_pourState", cStringArg);
			 Method m_setPourState = model.getClass().getMethod("setPourState", cStringArg);
			 
			 Method m_getRookie_pourBase=  model.getClass().getMethod("getRookie_pourBase", new Class[]{});
			 Method m_getRookie_pourStart = model.getClass().getMethod("getRookie_pourStart", new Class[]{});
			 
			 
			 Method m_getpourbase =  model.getClass().getMethod("getPourBase", new Class[]{});
			 Method m_getpourStart =  model.getClass().getMethod("getPourStart", new Class[]{});
			 
			 
			 BigDecimal rookie_pourbase =(BigDecimal) m_getRookie_pourBase.invoke(model);
			 BigDecimal rookie_pourstart =(BigDecimal) m_getRookie_pourStart.invoke(model);
			 BigDecimal rookie_newstart =  Helper.sub(rookie_pourstart, rookie_pourbase);
			 
			 BigDecimal pourbase =(BigDecimal) m_getpourbase.invoke(model);
			 BigDecimal pourstart =(BigDecimal) m_getpourStart.invoke(model);
			 BigDecimal newstart =  Helper.sub(pourstart, pourbase);
			 
			 //重置起始點
			 m_setPourStart.invoke(model, newstart);
			 m_setRookie_pourStart.invoke(model, rookie_newstart);
			 
			 //value
			 listDecimal.add(m_setWaterpool);
			 listDecimal.add(m_setPourBase);
			 listDecimal.add(m_setPourTotal);
			 listDecimal.add(m_setRookie_pourBase);
			 listDecimal.add(m_setRookie_pourTotal);
			 listDecimal.add(m_setRookie_waterpool);
			 
			 //state
			 listStr.add(m_setPourState);
			 listStr.add(m_setRookie_pourState);
			 
			 for(Method mm:listDecimal)			 
			 {
				 mm.invoke(model,BigDecimal.ZERO);
			 }
			 
			 for(Method ms:listStr)			 
			 {
				 ms.invoke(model, "CLOSE");
			 }
		} catch (NoSuchMethodException | SecurityException e) {
			e.printStackTrace();
		} catch (IllegalAccessException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (IllegalArgumentException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (InvocationTargetException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		
		
		return model;
	}
}




